iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 25
0

前言

昨天我們以 axios 的方式做切入,只有粗略提到一點 Ajax 。今天要把主角換成 Ajax ,深入底層的觀念。

語法

Ajax 主要有五個步驟:

  1. 首先宣告一個變數,讓他等於 XMLHttpRequest 。
  2. 把這個變數打開建立連線,並選擇打開的方式,設定是否同步。
  3. 確認連線完之後,才觸發某些函式。
  4. 設定後端要求的傳送格式,僅 post 須設定。
  5. 最後送出連線。

換成語法的話就會是下面這樣:

let xhr = new XMLHttpRequest();
xhr.open('post or get','api網址',true或false);
xhr.onload = function(要執行的事){};
xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded');
xhr.send('要傳送的資料');

用昨天的 API 來寫的話則是這樣:

let xhr = new XMLHttpRequest();
xhr.open('get','https://api.kcg.gov.tw/api/service/Get/b4dd9c40-9027-4125-8666-06bef1756092',true);
xhr.onload = function(){
    console.log(xhr.responseText);   
};
xhr.send();

application/x-www-form-urlencoded

application/x-www-form-urlencoded 是種在 post api 時常見的格式,這個位置會根據後端要求要用哪種格式傳送而改變。其他常見的格式還有: multipart/form-data 、 application/json 和 text/xml 。用不同的格式傳送,可能導致下面要把內容放到網站畫面,須把格式轉換成 JSON 格式,或把物件轉成字串。

例如使用 JSON.parse() 可把資料轉成 JSON 格式,用 JSON.stringfy() 則可把物件轉成字串。

xhr.send();

send 括弧裡要傳送的資料如果不只一筆,中間可以用 & 來連接。例如:

xhr.send('email=abc@gmail.com&password=123');

同步非同步

在上面 xhr.open 的第三格可以設定同步與非同步,這是什麼意思,又要如何設定呢?昨天在寫 axios 時,應該會發現有時候資料還沒 load 完,就跑下面的程式,非常困擾吧!但同樣的,如果今天要傳的資料很多,網頁一直卡在那不能處理其他的事情,導致使用者不知道現在是什麼狀況而直接按叉叉,也很母湯。

所以這裡就出現是否要同步的選擇題了。

但不管你想怎麼決定,讓我們繞回來談一下設定。跟直觀想的不同, true 在這裡代表非同步,也就是不等資料傳回來就讓程式碼繼續往下跑,等到回傳才自動回傳。 false 在這裡代表的是同步,也就是等資料回傳才繼續跑下面。

network 面板

此外,你也可以透過 network 面板確認是否所有東西都有運作中,以及後端回傳那些物件資料。開啟方式和 console 一樣,在網頁上按 f12 ,選 network。從 status 可以判斷每個檔案跑的狀況。

點選 xhr 的檔案,會秀出細部資料,可以在 header 裡看到是用哪種方式(get/post)取得資料的, status 是什麼,在 preview 則能看到回傳的資料。實際螢幕畫面如下:


post 與 get

在上面的 xhr.open 後面,不只可以設定 post ,設成 get 也一樣能夠取得資料。例如上面的例子中,我們使用的 method 就是 get 而不是 post 。那這兩種的差別是什麼呢?

使用 get 傳送資料時,資料會被放在 header 傳送,傳送過程會被放在網址上,因此不適合傳密碼等較隱密的資料。此外, get 的請求會被 cache 紀錄、受限 QueryString 長度限制,並且是運用 PHP 的 $GET['xxx'] 變數接受傳值。

post 則不同,是把資料放在訊息主體內傳送,不會被 cache 紀錄、資料長度無限制,並且是運用 PHP 的 $_POST['xxx'] 接受傳值。也是因為 get 和 post 把資料放在不同的地方,剛剛提到的 Content-type ,只有會把資料放在主體的 post 需要設定。

實際練習

我們可以利用上面學到的,用這個 API 製作一個簡易註冊登入面板,並加入兩個小功能,讓系統能確認帳號密碼不為空,以及送出後清空欄位。

  • html
<div class= "wrap">
  <div class = "submit">
    <form action = "index.html">
    <h4>E-Mail:</h4>
    <input type = "text" name = "emailSubmit" class = "emailSubmit" placeholder = "example@gmail.com">
    <h4>Password:</h4>
    <input type = "text" name = "passwordSubmit" class = "passwordSubmit" placeholder = "請輸入密碼">
    <input type = "submit" value = "註冊" class = "sendSubmit">
    </form>
  </div>

  <div class = "login">
    <form action = "index.html">
    <h4>E-Mail:</h4>
    <input type = "text" name = "emailLogin" class = "emailLogin" placeholder = "example@gmail.com">
    <h4>Password:</h4>
    <input type = "text" name = "passwordLogin" class = "passwordLogin" placeholder = "請輸入密碼">
    <input type = "submit" value = "登入" class = "sendLogin">
    </form>
  </div>
</div>
  • css
h4{
  margin-left: 15px;
}
.wrap{
  width: 600px;
  display: flex;
  margin: 0 auto;
}

input{
  margin: 15px;
}

.submit, .login{
  width: 500px;
  justify-content: space-evently;
  padding: 20px;
  margin-top: 40px;
}

.submit{
  background: #0077b6;
  color: #90e0ef;
}

.login{
  background: #90e0ef;
  color: #0077b6;
}

.sendLogin{
  background: #0077b6;
  color: #90e0ef;
  border: 0px;
  width: 200px;
}

.sendLogin:hover, .sendSubmit:hover{
  background: #e5989b;
  color: #6d6875;
}

.sendSubmit{
  background: #90e0ef;
  color: #0077b6;
  border: 0px;
  width: 200px;
}
  • js
//註冊

let sendSubmit = document.querySelector('.sendSubmit');
sendSubmit.addEventListener("click",runSubmit);

function runSubmit(e){
  e.preventDefault();
  let mailSubmit = document.querySelector('.emailSubmit').value;
  let passSubmit = document.querySelector('.passwordSubmit').value;
  
  if(mailSubmit == ''||passSubmit == ''){ //帳號密碼不可為空
    alert('請輸入帳號密碼');
  }else{
    let xhrSubmit = new XMLHttpRequest();
    xhrSubmit.open("post","https://hexschool-tutorial.herokuapp.com/api/signup",true);
    xhrSubmit.setRequestHeader("content-type","application/x-www-form-urlencoded");
    xhrSubmit.send("email="+mailSubmit+"&password="+passSubmit);
    xhrSubmit.onload=function (){
      if(xhrSubmit.value == ""){ //帳號密碼不可為空
        outmail.innerhtml = "請輸入帳號密碼"
      };
		let strSubmit= JSON.parse(xhrSubmit.responseText).message;
		alert(strSubmit);
	  }  
  }
  reset(); //送出後,欄位進行清空
}

//登入

let sendLogin = document.querySelector('.sendLogin');
sendLogin.addEventListener("click",runLogin);

function runLogin(e){
  e.preventDefault();
  let mailLogin = document.querySelector('.emailLogin').value;
  let passLogin = document.querySelector('.passwordLogin').value;
  
  if(mailLogin == ''||passLogin == ''){ //帳號密碼不可為空
    alert('請輸入帳號密碼');
  }else{
    let xhrLogin = new XMLHttpRequest();
  
    xhrLogin.open("post","https://hexschool-tutorial.herokuapp.com/api/signup",true);
    xhrLogin.setRequestHeader("content-type","application/x-www-form-urlencoded");
    xhrLogin.send("email="+mailLogin+"&password="+passLogin);

    xhrLogin.onload=function (){ 
		  let strLogin = JSON.parse(xhrLogin.responseText).message;
		  alert(strLogin);
	  } 
  }
  reset(); //送出後,欄位進行清空
}

function reset(){ //送出後,欄位進行清空
  document.querySelector('.emailSubmit').value = "";
  document.querySelector('.passwordSubmit').value = "";
  document.querySelector('.emailLogin').value = "";
  document.querySelector('.passwordLogin').value = "";
}

學習與參考資料

JS 學徒特訓班教學影片及練習題 47-48 關
什麼是 Ajax? 搞懂非同步請求 (Asynchronous request)概念: https://tw.alphacamp.co/blog/ajax-asynchronous-request
[鐵人賽Day2] GET/POST 的差異與配合PHP用法: https://ithelp.ithome.com.tw/articles/10155801
【POST】請求頭 Content-type: https://medium.com/@des75421/post-%E8%AB%8B%E6%B1%82%E9%A0%AD-content-type-82b93f9230f7


上一篇
24 Ajax 、 JSON 與 axios (上)
下一篇
26 正則表達式
系列文
花三十天找到 JavaScript 沙漠中的綠洲35
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言